package com.yugao.fintech.draper.redisson.aspect;

import cn.hutool.extra.spring.SpringUtil;
import com.yugao.fintech.draper.redisson.annotation.DistributedLock;
import com.yugao.fintech.draper.redisson.entity.LockEntity;
import com.yugao.fintech.draper.redisson.factory.RedissonLockServiceFactory;
import com.yugao.fintech.draper.redisson.resolver.DistributedLockResolver;
import com.yugao.fintech.draper.redisson.service.RedissonService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
import org.springframework.util.Assert;

@Slf4j
@Aspect
public class DistributedLockAspect implements Ordered {
    /**
     * 对带有DistributedLock注解的进行幂等处理，使用环绕通知
     */
    @Around(value = "@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
        // 获得key解析器
        DistributedLockResolver keyResolver = SpringUtil.getBean(distributedLock.lockResolver());
        Assert.notNull(keyResolver, "找不到对应的DistributedLockResolver");
        // 解析锁信息
        LockEntity lockEntity = keyResolver.resolver(joinPoint, distributedLock);
        // 根据锁类型 获取redissonService
        RedissonService redissonService = RedissonLockServiceFactory.getLock(distributedLock.lockType());
        // 如果当前线程持有当前锁，则重入
        if (redissonService.getThreadLock() != null && !lockEntity.equals(redissonService.getThreadLock())) {
            return joinPoint.proceed();
        }
        // 保存线程锁信息
        redissonService.saveThreadLock(lockEntity);
        // 加锁
        boolean success = redissonService.lock(lockEntity);
        try {
            // 锁定失败，抛出异常
            if (!success) {
                throw new RuntimeException("加锁失败！");
            } else {
                return joinPoint.proceed();
            }
        } finally {
            if (success) {
                // 释放锁
                redissonService.unlock(lockEntity);
                // 清空线程锁信息
                redissonService.clearThreadLock();
            }
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }

}
